//////////////////////////////////////
// Fast Container Library           //
// MIT License - Copyright (c) 2012 //
//////////////////////////////////////

#pragma once

#include "allocator.h"

FC_NAMESPACE_BEGIN


class pool_allocator : public allocator
{
public:
	struct header
	{
		header* next;
	};

	pool_allocator()
		: allocator(), m_head(0), m_poolBegin(0), m_poolEnd(0)
		{
		}

	pool_allocator( void* ptrMemory, size_t nBytes, size_t objectSize, size_t alignment )
		: allocator()
		{
			init( ptrMemory, nBytes, objectSize, alignment );
		}

	void init( void* ptrMemory, size_t nBytes, size_t objectSize, size_t alignment )
	{
		// requirement for pool allocators.
		if( objectSize < sizeof(void*) )
			objectSize = sizeof(void*);

		// align object size and memory ptr.
		objectSize = fc::align( objectSize, alignment );
		ptrMemory = fc::align( ptrMemory, alignment );

		// make sure we have enough room for objects.
		nBytes = (nBytes - (nBytes % objectSize));

		header* p = m_head = (header*)ptrMemory;
		for( size_t i(0); i < nBytes; i += objectSize )
		{
			p->next = (header*)((size_t)ptrMemory + i);
			p = p->next;
		}

		m_poolBegin = ptrMemory;
		m_poolEnd = (void*)((size_t)m_poolBegin + nBytes);
		p->next = 0;
	}

	void* allocate( size_t /*n*/, size_t /*alignment*/ = 0 )
	{
		header* p = (header*)m_head;
		if( p )
		{
			m_head = m_head->next;
			m_usedBlocks++;
		}

		return (void*)p;
	}

	void deallocate( void* ptr, size_t /*size*/ = 0 )
	{
		const bool isValid = owns_memory(ptr);
		FC_ASSERT(isValid);

		if( isValid )
		{
			header* p = m_head;
			m_head = (header*)ptr;
			m_head->next = p;
			m_usedBlocks--;
		}
	}

	bool can_allocate() const
	{
		return m_head != 0;
	}

	bool owns_memory( void* ptr ) const
	{
		return (ptr >= m_poolBegin && ptr < m_poolEnd);
	}

	pool_allocator& operator =( const pool_allocator& ) { return *this; }
	bool operator ==( const pool_allocator& ) const { return false; }
	bool operator ==( const allocator& ) const { return false; }

protected:
	header* m_head;
	void* m_poolBegin;
	void* m_poolEnd;
	size_t m_usedBlocks;

};



FC_NAMESPACE_END

